#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/init.h>

//--------------Working with list---------------------------------

static struct list_head stack;

struct stack_list {
	char byte;
	struct list_head list;
};

static int stack_add(char c)
{
	struct stack_list *b = NULL;
	b = kmalloc(sizeof(struct stack_list), GFP_KERNEL);
	if (!b) {
		printk("Memory didn't allocate\n");
		return -ENOMEM;
	}
	b->byte = c;
	list_add(&(b->list), &stack);

	printk("stack add: %c\n", c);
	return 0;
}

static char stack_read_del(void)
{
	struct stack_list *b = NULL;
	char c;

	b = list_first_entry(&stack, struct stack_list, list);	
	c = b->byte;
	list_del(&(b->list));
	kfree(b);

	printk("stack read end del: %c\n", c);
	return c;
}

//--------------Read and write operations-------------------------

ssize_t stack_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
{
	char c;

	if (list_empty(&stack)) {
		printk("Stack is empty\n");
		return 0;
	}

	c = stack_read_del();

	if (copy_to_user(buffer, &c, 1)) {
		printk("Byte not read from buffer\n");
		return -EFAULT;
	}

	*offset += 1;

	printk("stack read: %c\n", c);
	return 1;
}

ssize_t stack_write(struct file *file, const char __user *buffer, size_t count, loff_t *offset)
{
	int err = 0;
	char c;

	if (copy_from_user(&c, buffer, 1)) {
		printk("Byte not got from buffer\n");
		return -EFAULT;
	}

	err = stack_add(c);
	if (err != 0)
		return err;

	*offset += 1;

	printk("stack write: %c\n", c);
	return 1;
}

const struct file_operations stack_fops = {
	.read = stack_read,
	.write = stack_write,
	.owner = THIS_MODULE
};

static struct miscdevice stack_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "stack",
	.fops = &stack_fops
};


//--------------Module init/exit------------------------------------

static int __init stack_init(void)
{
	int err = 0;
	err = misc_register(&stack_dev);
	if (err != 0) {
		printk("Device didn't register\n");
		return err;
	}

	INIT_LIST_HEAD(&stack);

	printk("stack_init\n");
	return 0;
}

static void __exit exit_stack(void)
{
	misc_deregister(&stack_dev);
	printk("stack_exit\n");
}

module_init(stack_init)
module_exit(exit_stack)

//--------------Information about module----------------------------

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anastasiya Solomina <sterlyadka333@mail.ru>");
